<template>
    <div ref="tableSelectRef" :style="'width:' + width">
        <el-popover
            :visible="popoverVisible"
            :width="popoverWidth"
            placement="bottom-end"
            v-bind="selectConfig.popover"
            @show="handleShow"
        >
            <template #reference>
                <div @click="popoverVisible = !popoverVisible">
                    <slot>
                        <el-input
                            class="reference"
                            :model-value="text"
                            :readonly="true"
                            :placeholder="placeholder"
                        >
                            <template #suffix>
                                <el-icon
                                    :style="{
                                        transform: popoverVisible
                                            ? 'rotate(180deg)'
                                            : 'rotate(0)',
                                        transition: 'transform .5s',
                                    }"
                                >
                                    <ArrowDown />
                                </el-icon>
                            </template>
                        </el-input>
                    </slot>
                </div>
            </template>
            <!-- 弹出框内容 -->
            <div ref="popoverContentRef">
                <!-- 表单 -->
                <el-form ref="formRef" :model="queryParams" :inline="true">
                    <template
                        v-for="item in selectConfig.formItems"
                        :key="item.prop"
                    >
                        <el-form-item :label="item.label" :prop="item.prop">
                            <!-- Input 输入框 -->
                            <template v-if="item.type === 'input'">
                                <template v-if="item.attrs?.type === 'number'">
                                    <el-input
                                        v-model.number="queryParams[item.prop]"
                                        v-bind="item.attrs"
                                        @keyup.enter="handleQuery"
                                    />
                                </template>
                                <template v-else>
                                    <el-input
                                        v-model="queryParams[item.prop]"
                                        v-bind="item.attrs"
                                        @keyup.enter="handleQuery"
                                    />
                                </template>
                            </template>
                            <!-- Select 选择器 -->
                            <template v-else-if="item.type === 'select'">
                                <el-select
                                    v-model="queryParams[item.prop]"
                                    v-bind="item.attrs"
                                >
                                    <template
                                        v-for="option in item.options"
                                        :key="option.value"
                                    >
                                        <el-option
                                            :label="option.label"
                                            :value="option.value"
                                        />
                                    </template>
                                </el-select>
                            </template>
                            <!-- TreeSelect 树形选择 -->
                            <template v-else-if="item.type === 'tree-select'">
                                <el-tree-select
                                    v-model="queryParams[item.prop]"
                                    v-bind="item.attrs"
                                />
                            </template>
                            <!-- DatePicker 日期选择器 -->
                            <template v-else-if="item.type === 'date-picker'">
                                <el-date-picker
                                    v-model="queryParams[item.prop]"
                                    v-bind="item.attrs"
                                />
                            </template>
                            <!-- Input 输入框 -->
                            <template v-else>
                                <template v-if="item.attrs?.type === 'number'">
                                    <el-input
                                        v-model.number="queryParams[item.prop]"
                                        v-bind="item.attrs"
                                        @keyup.enter="handleQuery"
                                    />
                                </template>
                                <template v-else>
                                    <el-input
                                        v-model="queryParams[item.prop]"
                                        v-bind="item.attrs"
                                        @keyup.enter="handleQuery"
                                    />
                                </template>
                            </template>
                        </el-form-item>
                    </template>
                    <el-form-item>
                        <el-button
                            type="primary"
                            icon="search"
                            @click="handleQuery"
                        >
                            搜索
                        </el-button>
                        <el-button icon="refresh" @click="handleReset"
                            >重置</el-button
                        >
                    </el-form-item>
                </el-form>
                <!-- 列表 -->
                <el-table
                    ref="tableRef"
                    v-loading="loading"
                    :data="pageData"
                    :border="true"
                    :max-height="250"
                    :row-key="pk"
                    :highlight-current-row="true"
                    :class="{ radio: !isMultiple }"
                    @select="handleSelect"
                    @select-all="handleSelectAll"
                >
                    <template
                        v-for="col in selectConfig.tableColumns"
                        :key="col.prop"
                    >
                        <!-- 自定义 -->
                        <template v-if="col.templet === 'custom'">
                            <el-table-column v-bind="col">
                                <template #default="scope">
                                    <slot
                                        :name="col.slotName ?? col.prop"
                                        :prop="col.prop"
                                        v-bind="scope"
                                    />
                                </template>
                            </el-table-column>
                        </template>
                        <!-- 其他 -->
                        <template v-else>
                            <el-table-column v-bind="col" />
                        </template>
                    </template>
                </el-table>
                <!-- 分页 -->
                <pagination
                    v-if="total > 0"
                    v-model:total="total"
                    v-model:page="queryParams.pageNum"
                    v-model:limit="queryParams.pageSize"
                    @pagination="handlePagination"
                />
                <div class="feedback">
                    <el-button
                        type="primary"
                        size="small"
                        @click="handleConfirm"
                    >
                        {{ confirmText }}
                    </el-button>
                    <el-button size="small" @click="handleClear"
                        >清 空</el-button
                    >
                    <el-button size="small" @click="handleClose"
                        >关 闭</el-button
                    >
                </div>
            </div>
        </el-popover>
    </div>
</template>

<script lang="ts" setup>
import { ref, reactive, computed } from "vue";
import { onClickOutside, useResizeObserver } from "@vueuse/core";
import type { FormInstance, PopoverProps, TableInstance } from "element-plus";

// 对象类型
export type IObject = Record<string, any>;
// 定义接收的属性
export interface ISelectConfig<T = any> {
    // 宽度
    width?: string;
    // 占位符
    placeholder?: string;
    // popover组件属性
    popover?: Partial<Omit<PopoverProps, "visible" | "v-model:visible">>;
    // 列表的网络请求函数(需返回promise)
    indexAction: (queryParams: T) => Promise<any>;
    // 主键名(跨页选择必填,默认为id)
    pk?: string;
    // 多选
    multiple?: boolean;
    // 表单项
    formItems: Array<{
        // 组件类型(如input,select等)
        type?: "input" | "select" | "tree-select" | "date-picker";
        // 标签文本
        label: string;
        // 键名
        prop: string;
        // 组件属性
        attrs?: IObject;
        // 初始值
        initialValue?: any;
        // 可选项(适用于select组件)
        options?: { label: string; value: any }[];
    }>;
    // 列选项
    tableColumns: Array<{
        type?: "default" | "selection" | "index" | "expand";
        label?: string;
        prop?: string;
        width?: string | number;
        [key: string]: any;
    }>;
}
const props = withDefaults(
    defineProps<{
        selectConfig: ISelectConfig;
        text?: string;
    }>(),
    {
        text: "",
    }
);

// 自定义事件
const emit = defineEmits<{
    confirmClick: [selection: any[]];
}>();

// 主键
const pk = props.selectConfig.pk ?? "id";
// 是否多选
const isMultiple = props.selectConfig.multiple === true;
// 宽度
const width = props.selectConfig.width ?? "100%";
// 占位符
const placeholder = props.selectConfig.placeholder ?? "请选择";
// 是否显示弹出框
const popoverVisible = ref(false);
// 加载状态
const loading = ref(false);
// 数据总数
const total = ref(0);
// 列表数据
const pageData = ref<IObject[]>([]);
// 每页条数
const pageSize = 10;
// 搜索参数
const queryParams = reactive<{
    pageNum: number;
    pageSize: number;
    [key: string]: any;
}>({
    pageNum: 1,
    pageSize: pageSize,
});

// 计算popover的宽度
const tableSelectRef = ref();
const popoverWidth = ref(width);
useResizeObserver(tableSelectRef, (entries) => {
    popoverWidth.value = `${entries[0].contentRect.width}px`;
});

// 表单操作
const formRef = ref<FormInstance>();
// 初始化搜索条件
for (const item of props.selectConfig.formItems) {
    queryParams[item.prop] = item.initialValue ?? "";
}
// 重置操作
function handleReset() {
    formRef.value?.resetFields();
    fetchPageData(true);
}
// 查询操作
function handleQuery() {
    fetchPageData(true);
}

// 获取分页数据
function fetchPageData(isRestart = false) {
    loading.value = true;
    if (isRestart) {
        queryParams.pageNum = 1;
        queryParams.pageSize = pageSize;
    }
    props.selectConfig
        .indexAction(queryParams)
        .then((data) => {
            total.value = data.total;
            pageData.value = data.list;
        })
        .finally(() => {
            loading.value = false;
        });
}

// 列表操作
const tableRef = ref<TableInstance>();
// 数据刷新后是否保留选项
for (const item of props.selectConfig.tableColumns) {
    if (item.type === "selection") {
        item.reserveSelection = true;
        break;
    }
}
// 选择
const selectedItems = ref<IObject[]>([]);
const confirmText = computed(() => {
    return selectedItems.value.length > 0
        ? `已选(${selectedItems.value.length})`
        : "确 定";
});
function handleSelect(selection: any[], row: any) {
    if (isMultiple || selection.length === 0) {
        // 多选
        selectedItems.value = selection;
    } else {
        // 单选
        selectedItems.value = [selection[selection.length - 1]];
        tableRef.value?.clearSelection();
        tableRef.value?.toggleRowSelection(selectedItems.value[0], true);
        tableRef.value?.setCurrentRow(selectedItems.value[0]);
    }
}
function handleSelectAll(selection: any[]) {
    if (isMultiple) {
        selectedItems.value = selection;
    }
}
// 分页
function handlePagination() {
    fetchPageData();
}

// 弹出框
const isInit = ref(false);
// 显示
function handleShow() {
    if (isInit.value === false) {
        isInit.value = true;
        fetchPageData();
    }
}
// 确定
function handleConfirm() {
    if (selectedItems.value.length === 0) {
        ElMessage.error("请选择数据");
        return;
    }
    popoverVisible.value = false;
    emit("confirmClick", selectedItems.value);
}
// 清空
function handleClear() {
    tableRef.value?.clearSelection();
    selectedItems.value = [];
}
// 关闭
function handleClose() {
    popoverVisible.value = false;
}
const popoverContentRef = ref();
/* onClickOutside(tableSelectRef, () => (popoverVisible.value = false), {
  ignore: [popoverContentRef],
}); */
</script>

<style scoped lang="scss">
.reference :deep(.el-input__wrapper),
.reference :deep(.el-input__inner) {
    cursor: pointer;
}

.feedback {
    display: flex;
    justify-content: flex-end;
    margin-top: 6px;
}
// 隐藏全选按钮
.radio :deep(.el-table__header th.el-table__cell:nth-child(1) .el-checkbox) {
    visibility: hidden;
}
</style>
